
import config
import app.tools as tool
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt, SIGNAL
from app.tools.tree import TreeWidget, TreeWidgetItem
from app.tools.dialog import Dialog
from lib.redis import RedisFacotry
from lib.tools.type import RedisConnectType, TreeItemType
from lib.tools.compat import Dict
from lib.storage import Storage
from app.ui.icon import Icon



class Tree(object):

    def __init__(self, parent=None):
        self.parent = parent
        self.logger = parent.logger
        self.icon = Icon()
        self.tree_widget = TreeWidget(parent)
        self.tree_widget.setSortingEnabled(False)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tree_widget.sizePolicy().hasHeightForWidth())
        self.tree_widget.setSizePolicy(sizePolicy)
        self.tree_widget.setEnabled(True)
        self.tree_widget.setAcceptDrops(False)
        self.tree_widget.setLineWidth(5)
        self.tree_widget.setMidLineWidth(3)
        self.tree_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.tree_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.tree_widget.setTabKeyNavigation(True)
        self.tree_widget.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerItem)
        self.tree_widget.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerItem)
        self.tree_widget.setAutoExpandDelay(0)
        self.tree_widget.setUniformRowHeights(False)
        self.tree_widget.setObjectName(tool._from_utf8("tree_widget"))
        self.tree_widget.headerItem().setText(0, tool._from_utf8("connect manager"))
        self.tree_widget.setSortingEnabled(self.tree_widget.isSortingEnabled())
        self.tree_widget.headerItem().setIcon(0, self.icon.get(config.ICON_LOGO))
        self.tree_widget.on_double_clicked(self.double_click)
        self.tree_widget.on_context_menu(self.context_menu)
        # for info in config.REDIS_CLIENT:
        #     self._init_client(info)
        # self._init_cluster(config.REDIS_CLUSTER)
        self.initialize()

    def initialize(self):
        self.tree_widget.clear()
        storage = Storage()
        conns = storage.list()
        for conn in conns:
            id = conn['id']
            name = conn['name']
            auth = conn['auth']
            type = conn['type']
            if type == 0:
                host, port = conn['node']
                self._init_client((id, name, host, port, auth))
            elif type == 1:
                nodes = conn['nodes']
                info = (id, name, nodes, auth)
                self._init_cluster(info)

    def get_instance(self):
        return self.tree_widget

    def double_click(self, item, _):
        print(item.isExpanded())
        value = item.value
        type = value['type']
        if type == TreeItemType.Cluster:
            nodes = value['nodes']
            auth = value['auth']
            self._init_cluster_node(nodes, auth, item)
        elif type == TreeItemType.Node:
            factory = value['factory']
            self._init_key(factory, item)
        elif type == TreeItemType.Client:
            client_info = (value['ip'], int(value['port']), value['auth'])
            self._init_client_db(client_info, item)
        elif type == TreeItemType.Database:
            if Dict.hash_key(value, 'factory'):
                factory = value['factory']
            else:
                index = value['index']
                client_info = value['info']
                host, port, auth = client_info
                factory = RedisFacotry(type=RedisConnectType.Client,
                                       info=(host, port, index), auth=auth,
                                       logger=self.logger)
                item.value['factory'] = factory
            self._init_key(factory, item)
        elif type == TreeItemType.Key:
            pass
        else:
            pass

    def context_menu(self, pos):
        current_item = self.tree_widget.itemAt(pos)
        if not hasattr(current_item, 'value'):
            return
        current_value = current_item.value
        current_type = current_value['type']

        def connect_edit():
            from app.ui.dialog import Dialog
            from app.ui.client import ClientWidget
            from app.ui.cluster import ClusterWidget
            storage = Storage()
            current_connect_id = current_value['id']
            current_connect_info = storage.get(current_connect_id)
            edit_dialog = Dialog(self.parent, 'Connect Client')
            current_connect_type = current_connect_info['type']
            if current_connect_type == 0:
                edit_dialog.set_window_size(0.5)
                edit_widget = ClientWidget(self, edit_dialog)
            elif current_connect_type == 1:
                edit_dialog.set_window_size(0.8)
                edit_widget = ClusterWidget(self, edit_dialog)
            else:
                return
            edit_widget.set_data(current_connect_info)
            edit_dialog.show()

        def connect_remove():
            storage = Storage()
            current_connect_id = current_value['id']
            storage.delete(current_connect_id)
            self.initialize()

        def node_filter_key():
            value, ok = Dialog.input_text(self.get_instance(), 'filter', 'input filter key:')
            if ok is False:
                return
            value_is_empty = not value
            value = tool.qstring_to_string(value)
            current_item.clear()
            ip, port = current_value['ip'], current_value['port']
            current_factory = current_value['factory']
            self._init_key(current_factory, current_item, value)
            count = current_item.childCount()
            text_format = '{0}:{1} [{2}]' if value_is_empty else '{0}:{1} [{2}] [filter: {3}]'
            text = text_format.format(ip, port, count, value)
            current_item.set_text(tool._from_utf8(text))


        def node_refresh_key():
            current_item.clear()
            ip, port = current_value['ip'], current_value['port']
            current_factory = current_value['factory']
            self._init_key(current_factory, current_item)
            count = current_item.childCount()
            text = '{0}:{1} [{2}]'.format(ip, port, count)
            current_item.set_text(tool._from_utf8(text))


        def database_filter_key():
            value, ok = Dialog.input_text(self.get_instance(), 'filter', 'input filter key:')
            if ok is False:
                return
            value_is_empty = not value
            value = tool.qstring_to_string(value)
            current_item.clear()
            index = current_value['index']
            current_factory = current_value['factory']
            self._init_key(current_factory, current_item, value)
            count = current_item.childCount()
            text_format = 'db{0} [{1}]' if value_is_empty else 'db{0} [{1}] [filter: {2}]'
            text = text_format.format(index, count, value)
            current_item.set_text(tool._from_utf8(text))

        def database_refresh_key():
            current_item.clear()
            index = current_value['index']
            current_factory = current_value['factory']
            self._init_key(current_factory, current_item)
            count = current_item.childCount()
            text = 'db{0} [{1}]'.format(index, count)
            current_item.set_text(tool._from_utf8(text))

        def remove_key():
            name = current_value['name']
            factory = current_value['factory']
            factory.delete(name)
            current_item.remove()

        def disconnect():
            if Dict.hash_key(current_item.value, 'factory'):
                current_item.value.pop('factory')
            current_item.clear()

        menu = QtGui.QMenu(self.parent)
        if current_type in (TreeItemType.Cluster, TreeItemType.Client):
            menu.addAction('Edit', connect_edit)
            menu.addAction('Disconnect', disconnect)
            menu.addAction('Remove', connect_remove)
        elif current_type == TreeItemType.Node:
            menu.addAction('Filter', node_filter_key)
            menu.addAction('Refresh', node_refresh_key)
        elif current_type == TreeItemType.Database:
            if Dict.hash_key(current_value, 'factory'):
                menu.addAction('Filter', database_filter_key)
                menu.addAction('Refresh', database_refresh_key)
                menu.addAction('Disconnect', disconnect)
        elif current_type == TreeItemType.Key:
            menu.addAction('Remove', remove_key)
        menu.exec_(QtGui.QCursor.pos())

    def context_menu_event(self, e):
        print(type(e))
        item = self.tree_widget.currentItem()
        print(item.value)

    def _init_cluster(self, cluster_info):
        id, name, nodes, auth = cluster_info
        cluster = TreeWidgetItem(name, self.tree_widget)
        cluster.setIcon(0, self.icon.get(config.ICON_CLUSTER))
        cluster.value = {'type': TreeItemType.Cluster, 'id': id, 'nodes': nodes, 'auth': auth}

    def _init_cluster_node(self, nodes, auth, parent):
        parent.clear()
        nodes = [(host, port) for (host, port) in nodes]
        factory = RedisFacotry(type=RedisConnectType.Cluster, info=nodes, auth=auth, logger=self.logger)
        parent.value['factory'] = factory
        dict_size = factory.size()
        for node in nodes:
            ip, port = node
            dict_size_key = '%s:%s' % (ip, port)
            size = dict_size[dict_size_key] if Dict.hash_key(dict_size, dict_size_key) else 0
            node = TreeWidgetItem('%s:%d [%d]' % (ip, port, size), parent)
            node.setIcon(0, self.icon.get(config.ICON_SERVER))
            node.value = {'type': TreeItemType.Node, 'factory': factory, 'ip': ip, 'port': port, 'auth': auth}

    def _init_client(self, client_info):
        id, name, host, port, auth = client_info
        node = TreeWidgetItem(name, self.tree_widget)
        node.setIcon(0, self.icon.get(config.ICON_SERVER))
        node.value = {'type': TreeItemType.Client, 'id': id, 'ip': host, 'port': port, 'auth': auth}

    def _init_client_db(self, client_info, parent):
        parent.clear()
        host, port, auth = client_info
        for i in range(16):
            factory = RedisFacotry(type=RedisConnectType.Client, info=(host, port, i), auth=auth, logger=self.logger)
            size = factory.size()
            db = TreeWidgetItem('db%d [%d]' % (i, size), parent)
            db.setIcon(0, self.icon.get(config.ICON_DATABASE))
            db.value = {'type': TreeItemType.Database, 'index': i, 'info': client_info}
            del factory

    def _init_key(self, factory, parent, pattern='*'):
        parent.clear()
        names = factory.keys(pattern)
        names = sorted(names)
        for name in names:
            name = bytes(name)
            # if pattern is not None and not (name in pattern or pattern in name):
            #     continue
            type_name = factory.type(name)
            key = TreeWidgetItem('[%s] %s' % (type_name, name), parent)
            key.setIcon(0, self.icon.get(config.ICON_KEY))
            key.value = {'type': TreeItemType.Key, 'name': name, 'factory': factory}


